//
// Created by 廖海龙 on 2025/4/9.
//

#include "HelloHttpRequest.hpp"


HelloHttpRequest::HelloHttpRequest(const int connFd, const std::string &text) :
        logger("HelloHttpRequest"), connFd(connFd), method(), path(), version(), headers(),
        write2cache(false), headerWriten(false)
{
    logger.i("HelloHttpRequest::HelloHttpRequest(%p)", this);
    read(text);
}

HelloHttpRequest::~HelloHttpRequest()
{
    logger.i("HelloHttpRequest::~HelloHttpRequest(%p)", this);
}

int HelloHttpRequest::getConnFd() const noexcept
{
    return connFd;
}

std::shared_ptr<HelloRange> HelloHttpRequest::getRange()
{
    std::shared_ptr<HelloRange> range = std::make_shared<HelloRange>();
    range->start = -1;
    range->end = -1;

    auto it = headers.find("Range");
    if (it == headers.end())
    {
        return range;
    }

    std::string value = it->second;  // 例如：bytes=0-499
    std::smatch match;
    std::regex pattern(R"(bytes=(\d*)-(\d*))");

    if (std::regex_search(value, match, pattern))
    {
        // match[1] 是 start，match[2] 是 end，可能为空
        if (!match[1].str().empty())
        {
            range->start = std::stoll(match[1].str());
        }
        if (!match[2].str().empty())
        {
            range->end = std::stoll(match[2].str());
        }
    }

    return range;
}

std::string HelloHttpRequest::getRealUrl()
{
    std::unordered_map<std::string, std::string> query;
    bool ret = getQueryParams(query);
    if (!ret || query.empty())
    {
        logger.e("connFd[%d] has not query params?");
        return "";
    }
    auto find = query.find("url");
    if (find == query.end())
    {
        logger.e("connFd[%d] has not 'url' param?");
        return "";
    }
    return find->second;
}

bool HelloHttpRequest::getQueryParams(std::unordered_map<std::string, std::string> &query)
{
    query.clear();

    size_t pos = path.find('?');
    if (pos == std::string::npos)
    {
        return false;
    }

    std::string queryStr = path.substr(pos + 1);
    std::istringstream stream(queryStr);
    std::string pair;

    while (std::getline(stream, pair, '&'))
    {
        size_t eq = pair.find('=');
        if (eq != std::string::npos)
        {
            std::string key = urlDecode(pair.substr(0, eq));
            std::string value = urlDecode(pair.substr(eq + 1));
            query[key] = value;
        } else
        {
            std::string key = urlDecode(pair);
            query[key] = "";
        }
    }

    return true;
}

void HelloHttpRequest::setWrite2Cache(bool _write2cache)
{
    this->write2cache = _write2cache;
}

bool HelloHttpRequest::isWrite2Cache() const
{
    return this->write2cache;
}

void HelloHttpRequest::markHeaderWriten()
{
    this->headerWriten = true;
}

[[nodiscard]] bool HelloHttpRequest::needWriteHeader() const
{
    return !this->headerWriten;
}

void HelloHttpRequest::read(const std::string &text)
{
    // 示例：
//    GET /proxy?url=http://demo-videos.qnsdk.com/VR-Panorama-Equirect-Angular-4500k.mp4 HTTP/1.1\r\n
//    User-Agent: Lavf/61.7.100\r\n
//    Accept: */*\r\n
//    Range: bytes=0-\r\n
//    Connection: close\r\n
//    Host: 10.131.40.146:8898\r\n
//    Icy-MetaData: 1\r\n
//    \r\n

    std::istringstream stream(text);
    std::string line;

    // 第一行：请求行 -> method path version
    if (std::getline(stream, line))
    {
        size_t methodEnd = line.find(' ');
        size_t pathEnd = line.find(' ', methodEnd + 1);

        if (methodEnd != std::string::npos && pathEnd != std::string::npos)
        {
            method = line.substr(0, methodEnd);
            path = line.substr(methodEnd + 1, pathEnd - methodEnd - 1);
            version = line.substr(pathEnd + 1);
        }
    }

    // 后续行：请求头部
    while (std::getline(stream, line))
    {
        // 去除 \r（因为 \r\n 是换行符）
        if (!line.empty() && line.back() == '\r')
        {
            line.pop_back();
        }

        // 空行代表 header 结束
        if (line.empty()) break;

        size_t colon = line.find(':');
        if (colon != std::string::npos)
        {
            std::string key = line.substr(0, colon);
            std::string value = line.substr(colon + 1);

            // 去除可能前后的空格
            key.erase(0, key.find_first_not_of(" \t"));
            key.erase(key.find_last_not_of(" \t") + 1);
            value.erase(0, value.find_first_not_of(" \t"));
            value.erase(value.find_last_not_of(" \t") + 1);

            headers[key] = value;
        }
    }

//    logger.i("Parsed HTTP Request: method=%s, path=%s, version=%s", method.c_str(), path.c_str(),
//             version.c_str());
//    for (const auto &entry: headers)
//    {
//        logger.i("Header: %s = %s", entry.first.c_str(), entry.second.c_str());
//    }
}

std::string HelloHttpRequest::urlDecode(const std::string &in)
{
    std::string out;
    out.reserve(in.size());

    for (size_t i = 0; i < in.size(); ++i)
    {
        if (in[i] == '%' && i + 2 < in.size())
        {
            char hex[3] = {in[i + 1], in[i + 2], 0};
            if (isxdigit(hex[0]) && isxdigit(hex[1]))
            {
                out += static_cast<char>(std::strtol(hex, nullptr, 16));
                i += 2;
            } else
            {
                out += in[i]; // Invalid %, keep original
            }
        } else if (in[i] == '+')
        {
            out += ' '; // application/x-www-form-urlencoded style
        } else
        {
            out += in[i];
        }
    }
    return out;
}

std::string HelloHttpRequest::urlEncode(const std::string &in)
{
    std::ostringstream out;

    for (unsigned char c: in)
    {
        if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~')
        {
            out << c; // 保留字符
        } else if (c == ' ')
        {
            out << '+'; // 空格编码为 +
        } else
        {
            out << '%' << std::uppercase << std::hex << std::setw(2) << std::setfill('0') << int(c);
        }
    }

    return out.str();
}